home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Add-Ons / BBEdit / MacBob 1.0ß2 / Source / Bob / Interpreter.cp < prev    next >
Encoding:
Text File  |  1995-12-12  |  13.6 KB  |  683 lines  |  [TEXT/KAHL]

  1. /***
  2.   *
  3.   *    Interpreter.cp - bytecode interpreter
  4.   *
  5.   *    Original code: Copyright (c) 1991, by David Michael Betz.  All rights reserved
  6.   *    Modifications and additions: Copyright © by Christopher E. Hyde, 1995
  7.   *
  8.   ***/
  9.  
  10. #include "Bob.h"
  11.  
  12. #define    qTimeOpCodes    0
  13. #if qDebug
  14. #define    qDebugInterp    0
  15. #else
  16. #define    qDebugInterp    0
  17. #endif
  18.  
  19. #define    IsZero(x)            ((x)->fType == tInteger && (x)->fInt == 0)
  20. #define    IsTrue(x)            ((x)->fType != tNil && !IsZero(x))
  21.  
  22. // Argument check macros
  23. #define    CheckType(o,t)        { if IsNotType(o, t) { gPC = pc; BadType(o,t); } }
  24. #define    Check0(t)            { if IsNotType(0, t) Arg0Not(t); }
  25. #define    CheckInt0()        { if IsNotType(0, tInteger) { gPC = pc; Arg0NotInt(); } }
  26. #define    CheckInt1()        { if IsNotType(1, tInteger) { gPC = pc; Arg1NotInt(); } }
  27.  
  28. // Global variables
  29. CodePtr    cbase;                // the base code address
  30. CodePtr    gPC;                // global copy of the program counter
  31. Vector    code;                // the current code vector
  32. Value    stkbase;            // the runtime stack
  33. Value    stktop;                // the top of the stack
  34. Value    sp;                    // the stack pointer
  35. Value    fp;                    // the frame pointer
  36.  
  37. // External variables
  38. extern TValue    symbols;
  39.  
  40. // Forward declarations
  41. static void    Interpret    (int);
  42. static CodePtr    OpCall        (CodePtr pc);
  43. static CodePtr    OpReturn    (CodePtr pc);
  44. static CodePtr    OpSend        (CodePtr pc);
  45. static CodePtr    OpVRef        (CodePtr pc);
  46. static CodePtr    OpVSet        (CodePtr pc);
  47. static CodePtr    OpAdd        (CodePtr pc);
  48. /*static*/ KStr    TypeName    (int type);
  49.  
  50. char pSubsErr[] = "subscript out of bounds: %d";
  51.  
  52.  
  53. #if 0
  54. static int
  55. Fib (int n)
  56. {
  57.     return (n == 1 || n == 0)
  58.         ? 1
  59.         : Fib(n - 2) + Fib(n - 1);
  60. }
  61.  
  62.  
  63. static void
  64. PrintFib (int n)
  65. {
  66.     UInt32 tEnd, tStart = TickCount();
  67.     int result = Fib(n);
  68.  
  69.     tEnd = TickCount() - tStart;
  70.     PrintErrF("C - Fib(%d) = %d\r", n, result);
  71.     PrintErrF("    Executed in %d/60 seconds\r\r", tEnd);
  72. }
  73. #endif
  74.  
  75.  
  76. #if qTimeOpCodes
  77. static UInt32 pTickCount;
  78. #endif
  79.  
  80.  
  81. // Execute a bytecode function
  82. void
  83. Execute (KStr name)
  84. {
  85.         // lookup the symbol
  86.     Entry sym = FindEntry(&symbols, name);
  87.  
  88.     if (sym != nil) {
  89.             // setup the stack
  90.         sp = fp = stktop;
  91.         *--sp = sym->fValue;
  92.  
  93.         if (sp->fType == tByteCode) {
  94. #if 0
  95.             PrintFib(20);
  96.  
  97.             UInt32 t = TickCount();
  98.             Interpret(0);
  99.             PrintErrF("Executed in %d/60 seconds\r\r", TickCount() - t);
  100. #else
  101. #if qTimeOpCodes
  102.             pTickCount = TickCount();
  103. #endif
  104.             Interpret(0);
  105. #endif
  106.             return;
  107.         }
  108.     }
  109. //    Error("Cannot find the function ‘main’")
  110.     Fail(errNoMainFunction);
  111. }
  112.  
  113.  
  114. #define    qHack68K
  115. #if defined(qHack68K) && !__powerc
  116.  
  117. extern "C" {
  118. #pragma parameter __A0 GetPC
  119. extern pascal UInt16* GetPC (void) = { 0x41FA, 0 };        //    LEA    *,A0
  120. }
  121.  
  122. enum {
  123.     cLINK        =    0x4E56,        //    LINK        A6,#?
  124.     cMOVEM        =    0x48E7,        //    MOVEM.L    ?,-(A7)
  125.     cMOVEQ        =    0x7000,        //    MOVEQ    #0,D0
  126.     cMOVEB        =    0x1001,        //    MOVE.B    D1,D0
  127.     cMOVEQ_D1    =    0x72,
  128.     cCMPL        =    0xB081,        //    CMP.L    D1,D0
  129.     cBEQ        =    0x6700
  130. };
  131.  
  132.  
  133. // NOTE:  For this hack to work 
  134. void
  135. HackInterpretFn (void)
  136. {
  137.     UInt16* pc = GetPC();
  138.  
  139.         // First skip to start of next function
  140.     while (pc[0] != cLINK || pc[2] != cMOVEM)
  141. #if qDebugInterp
  142.         if (long(++pc) - long(GetPC()) > 750)
  143.             Error("HackFn: Can’t find Interpret fn\r");
  144. #else
  145.         ++pc;
  146. #endif
  147.  
  148.         // Search for start of switch statement
  149.     while (pc[0] != cMOVEQ || pc[1] != cMOVEB)
  150. #if qDebugInterp
  151.         if (long(++pc) - long(GetPC()) > 999)
  152.             Error("HackFn: Can’t find switch statement\r");
  153. #else
  154.         ++pc;
  155. #endif
  156.     pc += 2;
  157.  
  158.     UInt16* base = pc;
  159.     UInt16 offsets[_opLast + 1];
  160.  
  161.     for (int i = 0; i <= _opLast; ++i)
  162.         offsets[i] = 0;
  163.  
  164.         // Parse each:
  165.         //    72??            MOVEQ    #??,D1
  166.         //    B081            CMP.L    D1,D0
  167.         //    6700 ????        BEQ        *+????
  168.  
  169.     while ((pc[0] >> 8) == cMOVEQ_D1 && pc[1] == cCMPL && pc[2] == cBEQ) {
  170.         UInt8 opcode = pc[0];
  171. #if qDebugInterp
  172.         if (opcode < _opFirst || opcode > _opLast)
  173.             Error("HackFn: Bad opcode (0x%X)\r", opcode);
  174.         if (offsets[opcode] != 0)
  175.             Error("HackFn: Repeat opcode (0x%X)\r", opcode);
  176. #endif
  177.         offsets[opcode] = (long(pc) + 6) - (long(base) + 8) + pc[3];
  178.         pc += 4;
  179.     }
  180.  
  181.     pc = base;        // Save a copy of base
  182.  
  183.         // Now build the new switch instructions
  184.     *pc++ = 0x41FA;            // LEA        *+8,A0
  185.     *pc++ = 0x0006;
  186.     *pc++ = 0xD0F0;            // ADD.W        0(A0,D0.L*2),A0
  187.     *pc++ = 0x0A00;
  188.     *pc++ = 0x4ED0;            // JMP        (A0)
  189.  
  190.     for (i = _opFirst; i <= _opLast; ++i) {
  191. #if qDebugInterp
  192.         if (offsets[i] == 0)
  193.             Error("HackFn: Undefined opcode (0x%X)\r", i);
  194. #endif
  195.         *pc++ = offsets[i];
  196.     }
  197.  
  198.     FlushCodeCacheRange(base, long(pc) - long(base));
  199. //Debugger();
  200. }
  201. #endif    // qHack68K
  202.  
  203.  
  204. #define    DoBranch()    pc = cbase + (*(CWord*) pc)
  205. #define    _IntOp(X, OP)    {                                \
  206.                         CheckInt0();  CheckInt1();            \
  207.                         X (sp[1].fInt OP sp->fInt);            \
  208.                         ++sp;                        \
  209.                     }
  210. #define    IntEqOp(op)    _IntOp((void), op)
  211. #define    RelOp(rel)        {                                \
  212.                         _IntOp(n =, rel);                \
  213.                         set_integer(sp, n ? true : false);    \
  214.                     }
  215. enum {
  216.     kCommandKey        =    0x37,
  217.     kFullStopKey    =    0x2F
  218. };
  219. #define    TestKey(n)    (theKeys[(n) / 32] & (1 << ((n) % 32)))
  220.  
  221.  
  222. // Interpret bytecode instructions
  223. static void
  224. Interpret (int argc)
  225. {
  226.     CodePtr pc;                        // the program counter
  227.  
  228.     // make a dummy call frame
  229.     check(3);
  230.     code = sp[argc].fVec;
  231.     push_integer(argc);                // argument count
  232.     push_integer(stktop - fp);        // old fp
  233.     push_integer(0);                // old pc
  234.     cbase = pc = (CodePtr) code->fData[kIByteCodes].fStr->fData;
  235.     fp = sp;
  236.  
  237.     UInt16 nextCmdStop = 0;
  238.     for (;;) {                        // Execute each instruction
  239.         if (Opt(TraceExec)) {
  240.             DumpInstruction(code, pc - cbase);
  241.             nextCmdStop = 1;
  242.         }
  243.         if (--nextCmdStop == 0) {    // Minimize the overhead per instruction
  244.             KeyMap theKeys;
  245.             GetKeys(theKeys);
  246. #if qTimeOpCodes
  247.             static long testCount = 0;
  248.             ++testCount;
  249.             if (TestKey(kFullStopKey) && TestKey(kCommandKey))
  250.                 Error("errUserInterrupt: %d tests in %d ticks",
  251.                                         testCount, TickCount() - pTickCount);
  252. #else
  253.             if (TestKey(kFullStopKey) && TestKey(kCommandKey))
  254.                 Fail(errUserInterrupt);
  255. #endif
  256.         }
  257.         switch (*pc++) {
  258.         case opCALL:    pc = OpCall(pc);        break;
  259.         case opRTS:        pc = OpReturn(pc);
  260.                         if (pc == nil) return;
  261.                         break;
  262.         case opSEND:    pc = OpSend(pc);        break;
  263.         case opADD:        pc = OpAdd(pc);            break;
  264.         case opVREF:    pc = OpVRef(pc);        break;
  265.         case opVSET:    pc = OpVSet(pc);        break;
  266.         case opREF:
  267.                 *sp = code->fData[*pc++].fVar->fValue;
  268.                 break;
  269.         case opSET:
  270.                 code->fData[*pc++].fVar->fValue = *sp;
  271.                 break;
  272.         case opMREF:
  273.                 Object obj = fp[fp[2].fInt + 2].fObject;
  274.                 *sp = obj->fMembers[*pc++];
  275.                 break;
  276.         case opMSET:
  277.                 obj = fp[fp[2].fInt + 2].fObject;
  278.                 obj->fMembers[*pc++] = *sp;
  279.                 break;
  280.         case opAREF:
  281.                 int n = *pc++;
  282.                 if (n >= fp[2].fInt)
  283.                     Error("Too few arguments");
  284.                 *sp = fp[n + 3];
  285.                 break;
  286.         case opASET:
  287.                 n = *pc++;
  288.                 if (n >= fp[2].fInt)
  289.                     Error("Too few arguments");
  290.                 fp[n + 3] = *sp;
  291.                 break;
  292.         case opTREF:
  293.                 n = *pc++;
  294.                 *sp = fp[-n - 1];
  295.                 break;
  296.         case opTSET:
  297.                 n = *pc++;
  298.                 fp[-n - 1] = *sp;
  299.                 break;
  300.         case opTSPC:
  301.                 n = *pc++;
  302.                 check(n);
  303.                 while (--n >= 0) {
  304.                     --sp;
  305.                     set_nil(sp);
  306.                 }
  307.                 break;
  308.         case opBRT:
  309.                 if (IsTrue(sp))
  310.                     DoBranch();
  311.                 else
  312.                     pc += 2;
  313.                 break;
  314.         case opBRF:
  315.                 if (IsTrue(sp))
  316.                     pc += 2;
  317.                 else
  318.                     DoBranch();
  319.                 break;
  320.         case opBR:
  321.                 DoBranch();
  322.                 break;
  323.         case opNIL:
  324.                 set_nil(sp);
  325.                 break;
  326.         case opPUSH:
  327.                 check(1);
  328.                 push_integer(false);
  329.                 break;
  330.         case opNOT:
  331.                 set_integer(sp, !IsTrue(sp));
  332.                 break;
  333.         case opNEG:
  334.                 CheckInt0();
  335.                 sp->fInt = -sp->fInt;
  336.                 break;
  337.         case opSUB:        IntEqOp(-=);        break;
  338.         case opMUL:        IntEqOp(*=);        break;
  339.         case opDIV:
  340.                 CheckInt0();
  341.                 CheckInt1();
  342.                 if (sp->fInt != 0)
  343.                     sp[1].fInt /= sp->fInt;
  344.                 else
  345.                     sp[1].fInt = 0;
  346.                 ++sp;
  347.                 break;
  348.         case opREM:
  349.                 CheckInt0();
  350.                 CheckInt1();
  351.                 if (sp->fInt != 0)
  352.                     sp[1].fInt %= sp->fInt;
  353.                 else
  354.                     sp[1].fInt = 0;
  355.                 ++sp;
  356.                 break;
  357.         case opINC:
  358.                 CheckInt0();
  359.                 ++sp->fInt;
  360.                 break;
  361.         case opDEC:
  362.                 CheckInt0();
  363.                 --sp->fInt;
  364.                 break;
  365.         case opBAND:    IntEqOp(&=);        break;
  366.         case opBOR:        IntEqOp(|=);        break;
  367.         case opXOR:        IntEqOp(^=);        break;
  368.         case opBNOT:
  369.                 CheckInt0();
  370.                 sp->fInt = ~sp->fInt;
  371.                 break;
  372.         case opSHL:
  373. #if 1
  374.                 switch (sp[1].fType) {
  375.                 case tInteger:
  376.                     CheckInt0();
  377.                     sp[1].fInt <<= sp->fInt;
  378.                     break;
  379.                 case tStream:
  380.                     Print(&sp[1], false, &sp[0]);
  381.                     break;
  382.                 default:
  383.                     break;
  384.                 }
  385.                 ++sp;
  386. #else
  387.                 if (IsType(1, tStream)) {
  388.                     Print(&sp[1], false, &sp[0]);
  389.                     ++sp;
  390.                 } else
  391.                     IntEqOp(<<=);
  392. #endif
  393.                 break;
  394.         case opSHR:        IntEqOp(>>=);        break;
  395.         case opLT:        RelOp(<);            break;
  396.         case opLE:        RelOp(<=);            break;
  397.         case opEQ:        RelOp(==);            break;
  398.         case opNE:        RelOp(!=);            break;
  399.         case opGE:        RelOp(>=);            break;
  400.         case opGT:        RelOp(>);            break;
  401.         case opLIT:
  402.                 *sp = code->fData[*pc++];
  403.                 break;
  404.         case opDUP2:
  405.                 check(2);
  406.                 sp -= 2;
  407.                 *sp = sp[2];
  408.                 sp[1] = sp[3];
  409.                 break;
  410.         case opNEW:
  411.                 CheckType(0, tClass);
  412.                 gPC = pc;                // in case GC() is called
  413.                 set_object(sp, NewObject(sp));
  414.                 pc = gPC;
  415.                 break;
  416.         case opINT:
  417. //                set_integer(sp, *((CWord*) pc)++);
  418.                 set_integer(sp, *(CWord*) pc);
  419.                 pc += sizeof(CWord);
  420.                 break;
  421.         default:
  422.                 Error("Bad opcode %02X", pc[-1]);
  423.                 break;
  424.         }
  425.     }
  426. }
  427.  
  428.  
  429. // CALL opcode handler
  430. static CodePtr
  431. OpCall (CodePtr pc)
  432. {
  433.     register int n = *pc++;        // get argument count
  434.  
  435.     switch (sp[n].fType) {
  436.         case tCode:
  437.             gPC = pc;
  438.             (*sp[n].fCode)(n);
  439.             break;
  440.         case tByteCode:
  441.             check(3);
  442.             code = sp[n].fVec;
  443.             push_integer(n);                // argument count
  444.             push_integer(stktop - fp);        // old fp
  445.             push_integer(pc - cbase);        // old pc
  446.             cbase = pc = (CodePtr) code->fData[0].fStr->fData;
  447.             fp = sp;
  448.             break;
  449.         default:
  450.             Error("Call to non-procedure, Type %s", TypeName(sp[n].fType));
  451.             break;
  452.     }
  453.     return pc;
  454. }
  455.  
  456.  
  457. // RTS opcode handler
  458. static CodePtr
  459. OpReturn (CodePtr pc)
  460. {
  461.     TValue    val = *sp;
  462.  
  463.     sp = fp;
  464.     int pcoff = fp[0].fInt;
  465.     int n     = fp[2].fInt;
  466.     fp = stktop - fp[1].fInt;
  467.     if (fp == stktop)
  468.         return nil;
  469.     code = fp[fp[2].fInt + 3].fVec;
  470.     cbase = (CodePtr) code->fData[0].fStr->fData;
  471.     pc = cbase + pcoff;
  472.     sp += n + 3;
  473.     *sp = val;
  474.     return pc;
  475. }
  476.  
  477.  
  478. // SEND opcode handler
  479. static CodePtr
  480. OpSend (CodePtr pc)
  481. {
  482.     int n = *pc++;
  483.     CheckType(n, tObject);
  484.     CheckType(n - 1, tString);
  485.     Value aClass = objgetclass(&sp[n]);
  486.     TId selector;
  487.     GetCString(selector, sizeof(selector), &sp[n-1]);
  488.     sp[n - 1] = sp[n];
  489.     do {
  490.         Entry de;
  491.         if ((de = FindEntry(clgetfunctions(aClass), selector)) != nil) {
  492.             switch (de->fValue.fType) {
  493.             case tCode:
  494.                 (*de->fValue.fCode)(n);
  495.                 return pc;
  496.             case tByteCode:
  497.                 check(3);
  498.                 code = de->fValue.fVec;
  499.                 set_bytecode(&sp[n], code);
  500.                 push_integer(n);                // argument count
  501.                 push_integer(stktop - fp);        // old fp
  502.                 push_integer(pc - cbase);        // old pc
  503.                 cbase = pc = (CodePtr) code->fData[0].fStr->fData;
  504.                 fp = sp;
  505.                 return pc;
  506.             default:
  507.                 Error("Bad method, Selector ‘%s’, Type %d",
  508.                                     selector, de->fValue.fType);
  509.             }
  510.         }
  511.         aClass = clgetbase(aClass);
  512.     } while (!isnil(aClass));
  513.     Error("No method for selector ‘%s’", selector);
  514. //    return nil;        // Statement NOT reached
  515. }
  516.  
  517.  
  518. // VREF opcode handler
  519. static CodePtr
  520. OpVRef (CodePtr pc)
  521. {
  522.     CheckInt0();
  523.     switch (sp[1].fType) {
  524.     case tVector:
  525.         Vector vect = sp[1].fVec;
  526.         int i = sp[0].fInt;
  527.         if (i < 0 || i >= vect->fLength)
  528.             Error(pSubsErr, i);
  529.         sp[1] = vect->fData[i];
  530.         break;
  531.     case tString:
  532.         String str = sp[1].fStr;
  533.         i = sp[0].fInt;
  534.         if (i < 0 || i >= str->fLength)
  535.             Error(pSubsErr, i);
  536.         set_integer(&sp[1], str->fData[i]);
  537.         break;
  538.     default:
  539.         gPC = pc;
  540.         BadType(1, tVector);
  541.         break;
  542.     }
  543.     ++sp;
  544.     return pc;
  545. }
  546.  
  547.  
  548. // VSET opcode handler
  549. static CodePtr
  550. OpVSet (CodePtr pc)
  551. {
  552.     CheckInt1();
  553.     switch (sp[2].fType) {
  554.     case tVector:
  555.         Vector vect = sp[2].fVec;
  556.         int i = sp[1].fInt;
  557.         if (i < 0 || i >= vect->fLength)
  558.             Error(pSubsErr, i);
  559.         vect->fData[i] = sp[2] = *sp;
  560.         break;
  561.     case tString:
  562.         CheckInt0();
  563.         String str = sp[2].fStr;
  564.         i = sp[1].fInt;
  565.         if (i < 0 || i >= str->fLength)
  566.             Error(pSubsErr, i);
  567.         str->fData[i] = sp[0].fInt;
  568.         set_integer(&sp[2], str->fData[i]);
  569.         break;
  570.     default:
  571.         gPC = pc;
  572.         BadType(1, tVector);
  573.         break;
  574.     }
  575.     sp += 2;
  576.     return pc;
  577. }
  578.  
  579.  
  580. #define    TwoTypes(a, b)        (((a) << 4) + (b))
  581.  
  582. // ADD opcode handler
  583. static CodePtr
  584. OpAdd (CodePtr pc)
  585. {
  586.     switch (TwoTypes(sp[1].fType, sp[0].fType)) {
  587.     case TwoTypes(tInteger, tInteger):
  588.         sp[1].fInt += sp->fInt;
  589.         break;
  590.     case TwoTypes(tInteger, tString):
  591.         String sn = NewString(1 + SLen(sp));
  592.         String s2 = sp[0].fStr;
  593.         sn->fData[0] = sp[1].fInt;
  594.         memcpy(&sn->fData[1], s2->fData, s2->fLength);
  595.         set_string(&sp[1], sn);
  596.         break;
  597.     case TwoTypes(tString, tInteger):
  598.         sn = NewString(sp[1].fStr->fLength + 1);
  599.         String s1 = sp[1].fStr;
  600.         memcpy(sn->fData, s1->fData, s1->fLength);
  601.         sn->fData[s1->fLength] = sp[0].fInt;
  602.         set_string(&sp[1], sn);
  603.         break;
  604.     case TwoTypes(tString, tString):
  605.         sn = NewString(sp[1].fStr->fLength + SLen(sp));
  606.         s1 = sp[1].fStr;
  607.         s2 = sp[0].fStr;
  608.         memcpy(sn->fData, s1->fData, s1->fLength);
  609.         memcpy(&sn->fData[s1->fLength], s2->fData, s2->fLength);
  610.         set_string(&sp[1], sn);
  611.         break;
  612.     default:
  613.         gPC = pc;
  614.         BadType(1, tString);
  615.         break;
  616.     }
  617.     ++sp;
  618.     return pc;
  619. }
  620.  
  621.  
  622. // The type names
  623. static const char pTypeNames[][11] = {
  624.     "NIL", "INTEGER", "CODE",
  625.     "CLASS", "OBJECT", "VECTOR", "STRING",
  626.     "BYTECODE", "DICTIONARY", "VAR", "STREAM"
  627. };
  628.  
  629.  
  630. // Get the name of a type
  631. /*static*/ KStr
  632. TypeName (int type)
  633. {
  634.     if (type >= _tMin && type <= _tMax)
  635.         return pTypeNames[type];
  636.  
  637.     static char buf[kTypeNameSize];
  638.     sprintf(buf, "(%d)", type);
  639.     return buf;
  640. }
  641.  
  642.  
  643. void
  644. Arg0Not (int type)
  645. {
  646.     BadType(0, type);
  647. }
  648.  
  649.  
  650. void
  651. Arg0NotInt (void)
  652. {
  653.     BadType(0, tInteger);
  654. }
  655.  
  656.  
  657. void
  658. Arg1NotInt (void)
  659. {
  660.     BadType(1, tInteger);
  661. }
  662.  
  663.  
  664. // Report a bad operand type
  665. void
  666. BadType (int off, int type)
  667. {
  668.     char aType[kTypeNameSize];
  669.  
  670.     strcpy(aType, TypeName(sp[off].fType));
  671.     Info("PC: %04X, Offset %d, Type %s, Expected %s",
  672.          gPC - cbase, off, aType, TypeName(type));
  673.     Error("Bad argument type");
  674. }
  675.  
  676.  
  677. // Report a stack overflow error
  678. void
  679. StackOver (void)
  680. {
  681.     Error("Stack overflow");
  682. }
  683.